using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;

namespace DoItNow.UI
{
	public partial class SearchResultsControl : UserControl
	{
		private int _maxNumResults = 3;
		private int _firstResultToDisplay = 0;
		private int _highlightIndex = 0;
		private string _searchText = "";
		private List<SearchEntry> _searchEntries = new List<SearchEntry>();
		private List<SearchEntry> _searchResults = new List<SearchEntry>();

		public SearchResultsControl()
		{
			InitializeComponent();
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);

			if (DesignMode == true)
			{
				return;
			}

			int rowHeight = Font.Height + BorderHeight;

			Graphics graphics = e.Graphics;
			graphics.ResetClip();
			graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

			Rectangle drawArea = Rectangle.Inflate(ClientRectangle, -BorderHeight, -BorderHeight);

			for (int i = 0; i < NumDisplayEntries; ++i)
			{
				string name = _searchResults[i + _firstResultToDisplay].Name;
				string description = _searchResults[i + _firstResultToDisplay].Description;

				RectangleF layoutRectangle = new RectangleF(drawArea.Left, i * rowHeight + drawArea.Top, drawArea.Width, rowHeight);

				if (i == _highlightIndex)
				{
					graphics.FillRectangle(Brushes.AliceBlue, layoutRectangle);
					RectangleF outlineRectangle = new RectangleF(layoutRectangle.X, layoutRectangle.Y, layoutRectangle.Width - 1, layoutRectangle.Height - 1);

					graphics.DrawRectangle(Pens.Silver, Rectangle.Round(outlineRectangle));
				}

				string[] splitText = _searchText.ToLower().Split(' ');

				foreach (string s in splitText)
				{
					if (s.Length == 0)
						continue;

					int matchLocation = name.ToLower().IndexOf(s);

					CharacterRange[] characterRanges = new CharacterRange[] { new CharacterRange(matchLocation, s.Length) };

					StringFormat highlightFormat = new StringFormat();
					highlightFormat.LineAlignment = StringAlignment.Center;
					highlightFormat.SetMeasurableCharacterRanges(characterRanges);
					highlightFormat.Trimming = StringTrimming.EllipsisCharacter;
					highlightFormat.FormatFlags = StringFormatFlags.LineLimit;

					Region[] regions = new Region[1];
					regions = graphics.MeasureCharacterRanges(name, Font, layoutRectangle, highlightFormat);

					RectangleF matchRectangle = regions[0].GetBounds(graphics);
					graphics.FillRectangle(Brushes.Gainsboro, new RectangleF(matchRectangle.X, matchRectangle.Y + 1, matchRectangle.Width, matchRectangle.Height - 1));
				}

				StringFormat format = new StringFormat();
				format.LineAlignment = StringAlignment.Center;
				format.Trimming = StringTrimming.EllipsisCharacter;
				format.FormatFlags = StringFormatFlags.LineLimit;

				graphics.DrawString(name, Font, Brushes.Black, layoutRectangle, format);

				format.Alignment = StringAlignment.Far;

				graphics.DrawString(description, Font, Brushes.Gray, layoutRectangle, format);
			}
		}

		public void UpdateSearchResults(bool grow)
		{
			if (DesignMode == true)
			{
				return;
			}

			_highlightIndex = 0;

			if (_searchText.Length > 0)
			{
				string[] splitText = _searchText.ToLower().Split(' ');

				if (grow)
					_searchResults = _searchEntries;

				foreach (string s in splitText)
					_searchResults = _searchResults.FindAll(delegate(SearchEntry entry) { return entry.Name.ToLower().Contains(s); });

				_searchResults.Sort(new Comparison<SearchEntry>(CompareSearchEntries));
			}
			else
			{
				_searchResults.Clear();
			}

			Visible = _searchResults.Count > 0;
			Height = (BorderHeight * 2) + NumDisplayEntries * (BorderHeight + Font.Height) + 2;

			Invalidate();
		}

		private int CompareSearchEntries(SearchEntry lhs, SearchEntry rhs)
		{
			string searchTextLower = _searchText.ToLower();

			int compareByRelevance = (lhs.Name.ToLower().StartsWith(searchTextLower) ? 0 : 1) - ((rhs.Name.ToLower().StartsWith(searchTextLower) ? 0 : 1));
			return compareByRelevance == 0 ? String.Compare(lhs.Name, rhs.Name) : compareByRelevance;
		}

		public void SelectPreviousResult()
		{
			if (_highlightIndex == 0 && _firstResultToDisplay > 0)
			{
				_firstResultToDisplay--;
			}

			_highlightIndex = Math.Max(0, _highlightIndex - 1);
			Invalidate();
		}

		public void SelectNextResult()
		{
			if (_highlightIndex == (NumDisplayEntries - 1) && (_firstResultToDisplay + NumDisplayEntries) < _searchResults.Count)
			{
				_firstResultToDisplay++;
			}

			_highlightIndex = Math.Min(_highlightIndex + 1, NumDisplayEntries - 1);
			Invalidate();
		}

		public int MaxNumResults
		{
			get { return _maxNumResults; }
			set { _maxNumResults = value; }
		}

		public string SearchText
		{
			get { return _searchText; }
			set
			{
				bool growSearchResults = _searchText.Length == 0 || value.Length < _searchText.Length;
				_searchText = value.ToLower();
				UpdateSearchResults(growSearchResults);
			}
		}

		public List<SearchEntry> SearchEntries
		{
			set { _searchEntries = value; }
		}

		private int BorderHeight
		{
			get { return 3; }
		}

		private int NumDisplayEntries
		{
			get { return Math.Min(_searchResults.Count, _maxNumResults); }
		}

		private void OnMouseClick(object sender, MouseEventArgs e)
		{
			int rowHeight = Font.Height + BorderHeight;
			_highlightIndex = (e.Y - 3) / rowHeight;
			Invalidate();
		}

		public SearchEntry SelectedEntry
		{
			get { return _searchResults.Count == 0 ? new SearchEntry() : _searchResults[_firstResultToDisplay + _highlightIndex]; }
		}
	}
}